home *** CD-ROM | disk | FTP | other *** search
/ ASME's Mechanical Engine…ing Toolkit 1997 December / ASME's Mechanical Engineering Toolkit 1997 December.iso / main_frm / vi.zoo / cmdline.c < prev    next >
C/C++ Source or Header  |  1988-06-07  |  11KB  |  613 lines

  1. /*
  2.  * STevie - ST editor for VI enthusiasts.   ...Tim Thompson...twitch!tjt...
  3.  *
  4.  * Extensive modifications by:  Tony Andrews       onecom!wldrdg!tony
  5.  *
  6.  */
  7.  
  8. #include "stevie.h"
  9.  
  10. static    char    *altfile = NULL;    /* alternate file */
  11. static    int    altline;        /* line # in alternate file */
  12.  
  13. static    char    *nowrtmsg = "No write since last change (use ! to override)";
  14.  
  15. extern    char    **files;        /* used for "n" and "rew" */
  16. extern    int    numfiles, curfile;
  17.  
  18. /*
  19.  * The next two variables contain the bounds of any range given in a
  20.  * command. If no range was given, both contain null line pointers.
  21.  * If only a single line was given, u_pos will contain a null line
  22.  * pointer.
  23.  */
  24. static    LPTR    l_pos, u_pos;
  25.  
  26. static    bool_t    interactive;    /* TRUE if we're reading a real command line */
  27.  
  28. #define    CMDSZ    100        /* size of the command buffer */
  29.  
  30. static    bool_t    doecmd();
  31. static    void    badcmd(), doshell(), get_range();
  32. static    LPTR    *get_line();
  33.  
  34. #ifdef    MEGAMAX
  35. overlay "cmdline"
  36. #endif
  37.  
  38. /*
  39.  * readcmdline() - accept a command line starting with ':', '/', or '?'
  40.  *
  41.  * readcmdline() accepts and processes colon commands and searches. If
  42.  * 'cmdline' is null, the command line is read here. Otherwise, cmdline
  43.  * points to a complete command line that should be used. This is used
  44.  * in main() to handle initialization commands in the environment variable
  45.  * "EXINIT".
  46.  */
  47. void
  48. readcmdline(firstc, cmdline)
  49. int    firstc;        /* either ':', '/', or '?' */
  50. char    *cmdline;    /* optional command string */
  51. {
  52.     int c;
  53.     char buff[CMDSZ];
  54.     char *p, *q, *cmd, *arg;
  55.  
  56.     /*
  57.      * Clear the range variables.
  58.      */
  59.     l_pos.linep = (struct line *) NULL;
  60.     u_pos.linep = (struct line *) NULL;
  61.  
  62.     interactive = (cmdline == NULL);
  63.  
  64.     if (interactive)
  65.         gotocmd(1,1,firstc);
  66.     p = buff;
  67.     if ( firstc != ':' )
  68.         *p++ = firstc;
  69.  
  70.     if (interactive) {
  71.         /* collect the command string, handling '\b' and @ */
  72.         for ( ; ; ) {
  73.             c = vgetc();
  74.             if ( c=='\n'||c=='\r'||c==EOF )
  75.                 break;
  76.             if ( c=='\b' ) {
  77.                 if ( p > buff ) {
  78.                     p--;
  79.                     /* this is gross, but it relies
  80.                      * only on 'gotocmd'
  81.                      */
  82.                     gotocmd(1,0,firstc==':'?':':0);
  83.                     for ( q=buff; q<p; q++ )
  84.                         outchar(*q);
  85.                 } else {
  86.                     msg("");
  87.                     return;        /* back to cmd mode */
  88.                 }
  89.                 continue;
  90.             }
  91.             if ( c=='@' ) {
  92.                 p = buff;
  93.                 gotocmd(1,1,firstc);
  94.                 continue;
  95.             }
  96.             outchar(c);
  97.             *p++ = c;
  98.         }
  99.         *p = '\0';
  100.     } else {
  101.         if (strlen(cmdline) > CMDSZ-2)    /* should really do something */
  102.             return;            /* better here... */
  103.         strcpy(p, cmdline);
  104.     }
  105.  
  106.     /* skip any initial white space */
  107.     for ( cmd = buff; *cmd != NUL && isspace(*cmd); cmd++ )
  108.         ;
  109.  
  110.     /* search commands */
  111.     c = *cmd;
  112.     if ( c == '/' || c == '?' ) {
  113.         cmd++;
  114.         if ( *cmd == c ) {
  115.             /* the command was '//' or '??' */
  116.             repsearch();
  117.             return;
  118.         }
  119.         /* If there is a matching '/' or '?' at the end, toss it */
  120.         p = strchr(cmd, NUL);
  121.         if ( *(p-1) == c && *(p-2) != '\\' )
  122.             *(p-1) = NUL;
  123.         dosearch((c == '/') ? FORWARD : BACKWARD, cmd);
  124.         return;
  125.     }
  126.  
  127.     /*
  128.      * Parse a range, if present (and update the cmd pointer).
  129.      */
  130.     get_range(&cmd);
  131.  
  132.     /* isolate the command and find any argument */
  133.     for ( p=cmd; *p != NUL && ! isspace(*p); p++ )
  134.         ;
  135.     if ( *p == NUL )
  136.         arg = NULL;
  137.     else {
  138.         *p = NUL;
  139.         for (p++; *p != NUL && isspace(*p) ;p++)
  140.             ;
  141.         arg = p;
  142.         if ( *arg == '\0' )
  143.             arg = NULL;
  144.     }
  145.     if ( strcmp(cmd,"q!")==0 )
  146.         getout();
  147.     if ( strcmp(cmd,"q")==0 ) {
  148.         if ( Changed )
  149.             emsg(nowrtmsg);
  150.         else
  151.             getout();
  152.         return;
  153.     }
  154.     if ( strcmp(cmd,"w")==0 ) {
  155.         if ( arg == NULL ) {
  156.             if (Filename != NULL) {
  157.                 writeit(Filename, &l_pos, &u_pos);
  158.                 UNCHANGED;
  159.             } else
  160.                 emsg("No output file");
  161.         }
  162.         else
  163.             writeit(arg, &l_pos, &u_pos);
  164.         return;
  165.     }
  166.     if ( strcmp(cmd,"wq")==0 ) {
  167.         if (Filename != NULL) {
  168.             if ( writeit(Filename, NULL, NULL) )
  169.                 getout();
  170.         } else
  171.             emsg("No output file");
  172.         return;
  173.     }
  174.     if ( strcmp(cmd, "x") == 0 ) {
  175.         if (Changed) {
  176.             if (Filename != NULL) {
  177.                 if (!writeit(Filename, NULL, NULL))
  178.                     return;
  179.             } else {
  180.                 emsg("No output file");
  181.                 return;
  182.             }
  183.         }
  184.         getout();
  185.     }
  186.     if ( strcmp(cmd,"f")==0 && arg==NULL ) {
  187.         fileinfo();
  188.         return;
  189.     }
  190.     if ( *cmd == 'n' ) {
  191.         if ( (curfile + 1) < numfiles ) {
  192.             /*
  193.              * stuff ":e[!] FILE\n"
  194.              */
  195.             stuffin(":e");
  196.             if (cmd[1] == '!')
  197.                 stuffin("!");
  198.             stuffin(" ");
  199.             stuffin(files[++curfile]);
  200.             stuffin("\n");
  201.         } else
  202.             emsg("No more files!");
  203.         return;
  204.     }
  205.     if ( *cmd == 'p' ) {
  206.         if ( curfile > 0 ) {
  207.             /*
  208.              * stuff ":e[!] FILE\n"
  209.              */
  210.             stuffin(":e");
  211.             if (cmd[1] == '!')
  212.                 stuffin("!");
  213.             stuffin(" ");
  214.             stuffin(files[--curfile]);
  215.             stuffin("\n");
  216.         } else
  217.             emsg("No more files!");
  218.         return;
  219.     }
  220.     if ( strncmp(cmd, "rew", 3) == 0) {
  221.         if (numfiles <= 1)        /* nothing to rewind */
  222.             return;
  223.         curfile = 0;
  224.         /*
  225.          * stuff ":e[!] FILE\n"
  226.          */
  227.         stuffin(":e");
  228.         if (cmd[3] == '!')
  229.             stuffin("!");
  230.         stuffin(" ");
  231.         stuffin(files[0]);
  232.         stuffin("\n");
  233.         return;
  234.     }
  235.     if ( strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0 ) {
  236.         doecmd(arg, cmd[1] == '!');
  237.         return;
  238.     }
  239.     if ( strcmp(cmd,"f") == 0 ) {
  240.         Filename = strsave(arg);
  241.         filemess("");
  242.         return;
  243.     }
  244.     if ( strcmp(cmd,"r") == 0 || strcmp(cmd,".r") == 0 ) {
  245.         if ( arg == NULL ) {
  246.             badcmd();
  247.             return;
  248.         }
  249.         if (readfile(arg, Curschar, 1)) {
  250.             emsg("Can't open file");
  251.             return;
  252.         }
  253.         updatescreen();
  254.         CHANGED;
  255.         return;
  256.     }
  257.     if ( strcmp(cmd,".=")==0 ) {
  258.         char messbuff[80];
  259.         sprintf(messbuff,"line %d", cntllines(Filemem,Curschar));
  260.         msg(messbuff);
  261.         return;
  262.     }
  263.     if ( strcmp(cmd,"$=")==0 ) {
  264.         char messbuff[8];
  265.         sprintf(messbuff, "%d", cntllines(Filemem, Fileend)-1);
  266.         msg(messbuff);
  267.         return;
  268.     }
  269.     if ( strncmp(cmd,"ta", 2) == 0 ) {
  270.         dotag(arg, cmd[2] == '!');
  271.         return;
  272.     }
  273.     if ( strcmp(cmd,"set")==0 ) {
  274.         doset(arg, interactive);
  275.         return;
  276.     }
  277.     if ( strcmp(cmd,"help")==0 ) {
  278.         if (help()) {
  279.             screenclear();
  280.             updatescreen();
  281.         }
  282.         return;
  283.     }
  284.     if ( strcmp(cmd, "version") == 0) {
  285.         extern    char    *Version;
  286.  
  287.         msg(Version);
  288.         return;
  289.     }
  290.     if ( strcmp(cmd, "sh") == 0) {
  291.         doshell();
  292.         return;
  293.     }
  294.     /*
  295.      * If we got a line, but no command, then go to the line.
  296.      */
  297.     if (*cmd == NUL && l_pos.linep != NULL) {
  298.         *Curschar = l_pos;
  299.         cursupdate();
  300.         return;
  301.     }
  302.  
  303.     badcmd();
  304. }
  305.  
  306. /*
  307.  * get_range - parse a range specifier
  308.  *
  309.  * Ranges are of the form:
  310.  *
  311.  * addr[,addr]
  312.  *
  313.  * where 'addr' is:
  314.  *
  315.  * $  [+- NUM]
  316.  * 'x [+- NUM]    (where x denotes a currently defined mark)
  317.  * .  [+- NUM]
  318.  * NUM
  319.  *
  320.  * The pointer *cp is updated to point to the first character following
  321.  * the range spec. If an initial address is found, but no second, the
  322.  * upper bound is equal to the lower.
  323.  */
  324. static void
  325. get_range(cp)
  326. char    **cp;
  327. {
  328.     LPTR    *l;
  329.     char    *p;
  330.  
  331.     if ((l = get_line(cp)) == NULL)
  332.         return;
  333.  
  334.     l_pos = *l;
  335.  
  336.     for (p = *cp; *p != NUL && isspace(*p) ;p++)
  337.         ;
  338.  
  339.     *cp = p;
  340.  
  341.     if (*p != ',') {        /* is there another line spec ? */
  342.         u_pos = l_pos;
  343.         return;
  344.     }
  345.  
  346.     *cp = ++p;
  347.  
  348.     if ((l = get_line(cp)) == NULL) {
  349.         u_pos = l_pos;
  350.         return;
  351.     }
  352.  
  353.     u_pos = *l;
  354. }
  355.  
  356. static LPTR *
  357. get_line(cp)
  358. char    **cp;
  359. {
  360.     static    LPTR    pos;
  361.     LPTR    *lp;
  362.     char    *p, c;
  363.     int    lnum;
  364.  
  365.     pos.index = 0;        /* shouldn't matter... check back later */
  366.  
  367.     p = *cp;
  368.     /*
  369.      * Determine the basic form, if present.
  370.      */
  371.     switch (c = *p++) {
  372.  
  373.     case '$':
  374.         pos.linep = Fileend->linep->prev;
  375.         break;
  376.  
  377.     case '.':
  378.         pos.linep = Curschar->linep;
  379.         break;
  380.  
  381.     case '\'':
  382.         if ((lp = getmark(*p++)) == NULL) {
  383.             emsg("Unknown mark");
  384.             return (LPTR *) NULL;
  385.         }
  386.         pos = *lp;
  387.         break;
  388.  
  389.     case '0': case '1': case '2': case '3': case '4':
  390.     case '5': case '6': case '7': case '8': case '9':
  391.         for (lnum = c - '0'; isdigit(*p) ;p++)
  392.             lnum = (lnum * 10) + (*p - '0');
  393.  
  394.         pos = *gotoline(lnum);
  395.         break;
  396.  
  397.     default:
  398.         return (LPTR *) NULL;
  399.     }
  400.  
  401.     while (*p != NUL && isspace(*p))
  402.         p++;
  403.  
  404.     if (*p == '-' || *p == '+') {
  405.         bool_t    neg = (*p++ == '-');
  406.  
  407.         for (lnum = 0; isdigit(*p) ;p++)
  408.             lnum = (lnum * 10) + (*p - '0');
  409.  
  410.         if (neg)
  411.             lnum = -lnum;
  412.  
  413.         pos = *gotoline( cntllines(Filemem, &pos) + lnum );
  414.     }
  415.  
  416.     *cp = p;
  417.     return &pos;
  418. }
  419.  
  420. static void
  421. badcmd()
  422. {
  423.     if (interactive)
  424.         emsg("Unrecognized command");
  425. }
  426.  
  427. #define    LSIZE    512    /* max. size of a line in the tags file */
  428.  
  429. /*
  430.  * dotag(tag, force) - goto tag
  431.  */
  432. void
  433. dotag(tag, force)
  434. char    *tag;
  435. bool_t    force;
  436. {
  437.     FILE    *tp, *fopen();
  438.     char    lbuf[LSIZE];
  439.     char    *fname, *str;
  440.  
  441.     if ((tp = fopen("tags", "r")) == NULL) {
  442.         emsg("Can't open tags file");
  443.         return;
  444.     }
  445.  
  446.     while (fgets(lbuf, LSIZE, tp) != NULL) {
  447.     
  448.         if ((fname = strchr(lbuf, TAB)) == NULL) {
  449.             emsg("Format error in tags file");
  450.             return;
  451.         }
  452.         *fname++ = '\0';
  453.         if ((str = strchr(fname, TAB)) == NULL) {
  454.             emsg("Format error in tags file");
  455.             return;
  456.         }
  457.         *str++ = '\0';
  458.  
  459.         if (strcmp(lbuf, tag) == 0) {
  460.             if (doecmd(fname, force)) {
  461.                 stuffin(str);        /* str has \n at end */
  462.                 stuffin("\007");    /* CTRL('G') */
  463.                 fclose(tp);
  464.                 return;
  465.             }
  466.         }
  467.     }
  468.     emsg("tag not found");
  469.     fclose(tp);
  470. }
  471.  
  472. static    bool_t
  473. doecmd(arg, force)
  474. char    *arg;
  475. bool_t    force;
  476. {
  477.     int    line = 1;        /* line # to go to in new file */
  478.  
  479.     if (!force && Changed) {
  480.         emsg(nowrtmsg);
  481.         return FALSE;
  482.     }
  483.     if ( arg != NULL ) {
  484.         /*
  485.          * First detect a ":e" on the current file. This is mainly
  486.          * for ":ta" commands where the destination is within the
  487.          * current file.
  488.          */
  489.         if (Filename != NULL && strcmp(arg, Filename) == 0) {
  490.             if (!Changed || (Changed && !force))
  491.                 return TRUE;
  492.         }
  493.         if (strcmp(arg, "#") == 0) {    /* alternate */
  494.             char    *s = Filename;
  495.  
  496.             if (altfile == NULL) {
  497.                 emsg("No alternate file");
  498.                 return FALSE;
  499.             }
  500.             Filename = altfile;
  501.             altfile  = s;
  502.             line = altline;
  503.             altline = cntllines(Filemem, Curschar);
  504.         } else {
  505.             altfile = Filename;
  506.             altline = cntllines(Filemem, Curschar);
  507.             Filename = strsave(arg);
  508.         }
  509.     }
  510.     if (Filename == NULL) {
  511.         emsg("No filename");
  512.         return FALSE;
  513.     }
  514.  
  515.     /* clear mem and read file */
  516.     freeall();
  517.     filealloc();
  518.     UNCHANGED;
  519.  
  520.     readfile(Filename, Filemem, 0);
  521.     *Topchar = *Curschar;
  522.     if (line != 1) {
  523.         stuffnum(line);
  524.         stuffin("G");
  525.     }
  526.     setpcmark();
  527.     updatescreen();
  528.     return TRUE;
  529. }
  530.  
  531. static void
  532. doshell()
  533. {
  534.     char    *sh, *getenv();
  535.  
  536.     if ((sh = getenv("SHELL")) == NULL) {
  537.         emsg("Shell variable not set");
  538.         return;
  539.     }
  540.     gotocmd(TRUE, FALSE, 0);
  541.  
  542.     if (system(sh) < 0) {
  543.         emsg("Exec failed");
  544.         return;
  545.     }
  546.  
  547.     wait_return();
  548. }
  549.  
  550. void
  551. gotocmd(clr, fresh, firstc)
  552. bool_t  clr, fresh;
  553. char    firstc;
  554. {
  555.     int n;
  556.  
  557.     windgoto(Rows-1,0);
  558.     if ( clr )
  559.         outstr(T_EL);        /* clear the bottom line */
  560.     if ( firstc )
  561.         outchar(firstc);
  562. }
  563.  
  564. /*
  565.  * msg(s) - displays the string 's' on the status line
  566.  */
  567. void
  568. msg(s)
  569. char *s;
  570. {
  571.     gotocmd(TRUE, TRUE, 0);
  572.     outstr(s);
  573. }
  574.  
  575. void
  576. smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  577. char    *s;
  578. int    a1, a2, a3, a4, a5, a6, a7, a8, a9;
  579. {
  580.     char    sbuf[80];
  581.  
  582.     sprintf(sbuf, s, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  583.     msg(sbuf);
  584. }
  585.  
  586. /*
  587.  * emsg() - display an error message
  588.  *
  589.  * Rings the bell, if appropriate, and calls message() to do the real work
  590.  */
  591. void
  592. emsg(s)
  593. char    *s;
  594. {
  595.     if (P(P_EB))
  596.         beep();
  597.     msg(s);
  598. }
  599.  
  600. void
  601. wait_return()
  602. {
  603.     char    c;
  604.  
  605.     outstr("Press RETURN to continue");
  606.     do {
  607.         c = vgetc();
  608.     } while (c != '\r' && c != '\n');
  609.  
  610.     screenclear();
  611.     updatescreen();
  612. }
  613.